package com.zuokun.server;
import com.zuokun.handler.ServerHandler;
import com.zuokun.properties.ServerProperties;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.buffer.ByteBuf;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

@Component
@Slf4j
public class GameServer {

    @Autowired
    private ServerProperties serverProperties;

    @PostConstruct
    public void run() throws RuntimeException {
        new Thread(() -> {
            //接收客户端连接的线程组，这里一个线程就够了
            EventLoopGroup bossGroup = new NioEventLoopGroup(1);
            //处理读写事件的线程组
            EventLoopGroup workerGroup = new NioEventLoopGroup();
            try {
                //Netty服务器启动类，负责配置服务器各项参数并启动监听
                ServerBootstrap b = new ServerBootstrap();
                //设置上面创建的两个线程组
                b.group(bossGroup, workerGroup)
                        .channel(NioServerSocketChannel.class)
                        //设置子通道的初始化器，新的客户端连接会调用
                        .childHandler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            public void initChannel(SocketChannel ch) {
                                //获取Netty的处理器链，并为这个连接添加一个业务处理器
                                ch.pipeline().addLast(new ServerHandler());
                            }
                        })
                        //设置等待队列的最大长度
                        .option(ChannelOption.SO_BACKLOG, 128)
                        //开启TCP长连接探测机制
                        .childOption(ChannelOption.SO_KEEPALIVE, true);
                //异步绑定端口(默认ip是0.0.0.0)，启动服务，并等待完成后才进入下一步
                ChannelFuture f = b.bind(serverProperties.getPort()).sync();
                log.info("游戏服务器启动，端口：{}",serverProperties.getPort());
                //等待服务器关闭，主线程会阻塞在这里
                f.channel().closeFuture().sync();

            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                //不管启动成功与否，推出前都要优雅关闭线程组
                workerGroup.shutdownGracefully();
                bossGroup.shutdownGracefully();
            }
        }).start();
    }
}